package com.jifeng.api.crud.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jifeng.api.crud.dao.UserDao;
import com.jifeng.api.crud.entity.*;
import com.jifeng.api.crud.service.*;
import com.jifeng.api.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpSession;
import java.util.*;
import java.util.stream.Collectors;


@Service("userService")
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {

    @Autowired
    UserMenuService userMenuService;

    @Autowired
    MenuService menuService;

    @Autowired
    OrderService orderService;

    @Autowired
    TerminalService terminalService;

    @Autowired
    HeartService heartService;

    @Autowired
    DeviceService deviceService;

    @Autowired
    UserService userService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        Object name = params.get("name");
        Object account = params.get("account");
        Object province = params.get("province");
        Object city = params.get("city");
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();

        // 查询用户类型为 户主
        queryWrapper.eq("type", 2);

        if (name != null && !StringUtils.isEmpty(name.toString())) {
            name = name.toString();
            queryWrapper.like("name", name);
        }

        if (account != null && !StringUtils.isEmpty(account.toString())) {
            account = account.toString();
            queryWrapper.like("account", account);
        }

        if (province != null && !StringUtils.isEmpty(province.toString())) {
            queryWrapper.eq("province", province);
        }

        if (city != null && !StringUtils.isEmpty(city.toString())) {
            queryWrapper.eq("city", city);
        }

        IPage<UserEntity> page = this.page(
                new Query<UserEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    @Override
    public R login(UserEntity user) {
        try {
            // 返回结果map
            Map<String, Object> rsMap = new HashMap<>();

            // 获取传递参数
            String account = user.getAccount();
            String password = user.getPassword();

            // 查询该用户
            UserEntity userEntity = this.getOne(new QueryWrapper<UserEntity>()
                    .eq("account", account), false
            );

            /**
             * 判断用户是否存在
             */
            if (userEntity == null) {
                log.error("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "该用户不存在", "传入的account无效");
                return R.error("该用户不存在");
            }

            /**
             * 判断用户密码是否为空
             */
            String pwd = userEntity.getPassword();
            if (StringUtils.isEmpty(pwd)) {
                log.error("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "该用户未设置密码", "password字段为Null");
                return R.error("该用户未设置密码");
            }

            /**
             * 校验密码是否正确
             */
//            boolean checkpw = BCrypt.checkpw(password, pwd);
//            if (!checkpw) {
//                log.warn("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "密码错误");
//                return R.error(400, "密码错误");
//            }
            if (!password.equals(userEntity.getPassword())) {
                log.warn("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "密码错误", "传入的password与数据库中的不一致");
                return R.error("密码错误");
            }

            /**
             * 获取token
             */
            String token = HttpUtils.getToken(account, password);
            if (token.equals("")) {
                log.error("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "创建token失败", "返回的token为null");
                return R.error("创建token失败");
            }
            rsMap.put("token", token);

            /**
             * 查询用户类型
             */
            Integer type = userEntity.getType();
            if (type == null) {
                log.error("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "该用户类型未设置", "数据库中type字段为Null");
                return R.error("该用户类型未设置");
            }
            rsMap.put("type", type);
            rsMap.put("id", userEntity.getId());

            /**
             * 查询该用户类型的菜单
             */
            UserMenuEntity userMenuEntity = userMenuService.getOne(new QueryWrapper<UserMenuEntity>().eq("user_type", type), false);
            if (userMenuEntity == null) {
                log.warn("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "用户类型无效", "数据库中无该记录");
                return R.error("用户类型无效");
            }

            String pathIds = userMenuEntity.getPathIds();
            if (StringUtils.isEmpty(pathIds)) {
                log.warn("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "未找到用户所属的菜单", "数据库中path_ids字段为Null");
                return R.error("未找到用户所属的菜单");
            }

            String[] paths = pathIds.split(",");
            List<MenuEntity> menuEntityList = new ArrayList<>();
            for (String pathId : paths) {
                MenuEntity menuEntity = menuService.getById(pathId);
                if (menuEntity == null) {
                    continue;
                }
                menuEntityList.add(menuEntity);
            }

            // 找到所有的一级分类
            List<MenuEntity> collect = menuEntityList.stream().filter(menuEntity -> menuEntity.getParentId() == 0)
                    .map(menu -> {
                        menu.setChildren(getChildrens(menu, menuEntityList));
                        return menu;
                    }).collect(Collectors.toList());
            rsMap.put("list", collect);
            return R.ok().put("data", rsMap);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("path：{}，errMsg：{}", getRequestUrl(), e.getMessage());
            return R.sysError();
        }
    }

    @Override
    public R countData() {
        try {
            Map<String, Object> mapList = new HashMap<>();
            Map<String, Object> summary = new HashMap<>();
            Map<String, Object> terminal = new HashMap<>();
            Map<String, Object> device = new HashMap<>();
            Map<String, Object> orderUser = new HashMap<>();
            Map<String, Object> user = new HashMap<>();

            /**
             * 统计订单表中的数据
             */
            List<OrderEntity> orderEntities = orderService.list(new UpdateWrapper<OrderEntity>().eq("state", 7));
            // 统计订单中已清算（state=7)的金额
            int orderCount = orderEntities.size();
            // 统计 已清算，且end_time为当前月的订单
            int thisMonth = DateUtil.month(new Date());
            int monthCount = (int) orderEntities.stream().filter(orderEntity -> {
                Date endFeeTime = orderEntity.getEndFeeTime();
                if (endFeeTime == null) {
                    return false;
                }
                int month = DateUtil.month(orderEntity.getEndFeeTime());
                return thisMonth == month;
            }).count();
            // 统计 已清算，且end_time为当日的订单
            int thisDay = DateUtil.dayOfMonth(new Date());
            int dayCount = (int) orderEntities.stream().filter(orderEntity -> {
                Date endFeeTime = orderEntity.getEndFeeTime();
                if (endFeeTime == null) {
                    return false;
                }
                int day = DateUtil.dayOfMonth(endFeeTime);
                return thisDay == day;
            }).count();
            summary.put("total", orderCount);
            summary.put("month", monthCount);
            summary.put("daily", dayCount);

            /**
             * 统计机柜表中的数据
             */
            List<TerminalEntity> terminalEntities = terminalService.list();
            // 机柜表中的数量
            int terminalCount = terminalEntities.size();
            // 统计 tb_heart表中，当前时间-rev_time <180S的机柜数量
            List<HeartEntity> heartEntities = heartService.list();
            long terminalOnlineCount = heartEntities.stream().filter(heartEntity -> {
                Date revTime = heartEntity.getRevTime();
                if (revTime == null) {
                    return false;
                }
                long second = DateUtil.between(revTime, new Date(), DateUnit.SECOND);
                return second < 180;
            }).count();
            terminal.put("total", terminalCount);
            terminal.put("online", terminalOnlineCount);

            /**
             * 统计监视器总数
             */
            int deviceCount = deviceService.list().size();
            device.put("device", deviceCount);

            /**
             * 统计用户总数
             */
            // 订单表中的记录数 state >=3 & state<=7
            int orderSize = orderService.list(new UpdateWrapper<OrderEntity>().ge("state", 3).le("state", 7)).size();
            // 当前订单数 订单表中的记录数 state >=3 & state<=6
            int orderSize2 = orderService.list(new UpdateWrapper<OrderEntity>().ge("state", 3).le("state", 6)).size();
            orderUser.put("total", orderSize);
            orderUser.put("current", orderSize2);
            /**
             * 统计户主总数
             */
            int userCount = userService.list().size();
            user.put("total", userCount);

            /**
             * 装箱
             */
            mapList.put("summary", summary);
            mapList.put("terminal", terminal);
            mapList.put("device", device);
            mapList.put("orderUser", orderUser);
            mapList.put("user", user);
            return R.ok().put("data", mapList);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("path：{}，errMsg：{}", getRequestUrl(), e.getMessage());
            return R.sysError();
        }
    }

    @Override
    public R add(UserEntity userEntity) {
        try {
            String account = userEntity.getAccount();
            List<UserEntity> userEntities = this.list(new QueryWrapper<UserEntity>().eq("account", account));

            /**
             * 校验用户的唯一性
             */
            if (!userEntities.isEmpty()) {
                log.warn("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "用户已存在", "account字段值数据库已存在");
                return R.error("用户已存在");
            }

            // 设置用户类型为户主
            userEntity.setType(2);
            boolean addRs = this.save(userEntity);
            if (!addRs) {
                log.warn("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "增加新用户失败", "传递的参数与数据库字段不匹配");
                return R.error("增加新用户失败");
            }
            return R.ok();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("path：{}，errMsg：{}", getRequestUrl(), e.getMessage());
            return R.sysError();
        }
    }

    @Override
    public R updPassword(UserEntity userEntity) {
        try {
            Integer userId = userEntity.getId();
            UserEntity user = this.getById(userId);

            /**
             * 校验用户有效性
             */
            if (user == null) {
                log.warn("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "用户不存在", "所传id字段数据库不存在");
                return R.error(404, "用户不存在");
            }

            UserEntity updUser = new UserEntity();
            updUser.setId(userId);
            updUser.setPassword(userEntity.getPassword());
            boolean updUserRs = this.updateById(updUser);
            if (!updUserRs) {
                log.warn("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "修改密码失败", "所传password字段有误");
                return R.error("修改密码失败");
            }
            return R.ok();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("path：{}，errMsg：{}", getRequestUrl(), e.getMessage());
            return R.sysError();
        }
    }

    @Override
    public R del(UserEntity userEntity) {
        try {
            UserEntity user = this.getById(userEntity.getId());

            /**
             * 校验用户有效性
             */
            if (user == null) {
                log.warn("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "用户不存在", "所传id字段数据库不存在");
                return R.error(404, "用户不存在");
            }

            boolean delRs = this.removeById(user);
            if (!delRs) {
                log.warn("path：{}，errMsg：{}，cause：{}", getRequestUrl(), "删除用户失败", "未知原因");
                return R.error("删除用户失败");
            }
            return R.ok();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("path：{}，errMsg：{}", getRequestUrl(), e.getMessage());
            return R.sysError();
        }
    }

    @Override
    public R listByProvince(Map<String, Object> params) {
        try {
            String province = params.get("province").toString();
            String city = params.get("city").toString();

            List<UserEntity> userEntities = this.list(new QueryWrapper<UserEntity>().eq("province", province).eq("city", city));
            if (userEntities.isEmpty()) {
                return R.error().put("data", userEntities);
            }
            return R.ok().put("data", userEntities);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("path：{}，errMsg：{}", getRequestUrl(), e.getMessage());
            return R.sysError();
        }
    }

    private List<MenuEntity> getChildrens(MenuEntity root, List<MenuEntity> all) {
        List<MenuEntity> children = all.stream().filter(menuEntity -> menuEntity.getParentId() == root.getId())
                // 找到子菜单
                .map(menuEntity -> {
                    menuEntity.setChildren(getChildrens(menuEntity, all));
                    return menuEntity;
                })
                .collect(Collectors.toList());
        return children;
    }

    public String getRequestUrl() {
        return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest().getRequestURI();
    }
}